package tools

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mcp-clarification-service/internal/protocol"
	"net/http"
	"sync"
	"time"
)

// ToolInvocation 工具调用
type ToolInvocation struct {
	ID         string
	ToolName   string
	Params     json.RawMessage
	ResponseCh chan *protocol.ToolResult
	ErrorCh    chan error
	Deadline   time.Time
}

// RequestGuard 请求守卫
type RequestGuard struct {
	mu     sync.Mutex
	active bool
}

// Acquire 获取锁
func (g *RequestGuard) Acquire() error {
	g.mu.Lock()
	defer g.mu.Unlock()
	if g.active {
		return fmt.Errorf("another request is in progress")
	}
	g.active = true
	return nil
}

// Release 释放锁
func (g *RequestGuard) Release() {
	g.mu.Lock()
	defer g.mu.Unlock()
	g.active = false
}

// HTTPClient 简单的HTTP客户端接口
type HTTPClient struct {
	baseURL    string
	httpClient *http.Client
	timeout    time.Duration
}

// NewHTTPClient 创建HTTP客户端
func NewHTTPClient(baseURL string, timeout time.Duration) *HTTPClient {
	return &HTTPClient{
		baseURL: baseURL,
		httpClient: &http.Client{
			Timeout: timeout,
		},
		timeout: timeout,
	}
}

// AskQuestions 发送请求
func (c *HTTPClient) AskQuestions(questions []Question, timeout int) ([]Answer, bool, error) {
	req := map[string]interface{}{
		"questions": questions,
		"timeout":   timeout,
	}

	data, err := json.Marshal(req)
	if err != nil {
		return nil, false, fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := c.httpClient.Post(c.baseURL+"/ask", "application/json", bytes.NewReader(data))
	if err != nil {
		return nil, false, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusConflict {
		return nil, false, fmt.Errorf("another request is in progress")
	}

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, false, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
	}

	var result struct {
		Answers   []Answer `json:"answers"`
		Cancelled bool     `json:"cancelled"`
		Error     string   `json:"error,omitempty"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, false, fmt.Errorf("failed to decode response: %w", err)
	}

	if result.Error != "" {
		return nil, false, fmt.Errorf("GUI error: %s", result.Error)
	}

	return result.Answers, result.Cancelled, nil
}

// HealthCheck 健康检查
func (c *HTTPClient) HealthCheck() (bool, error) {
	resp, err := c.httpClient.Get(c.baseURL + "/health")
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()

	return resp.StatusCode == http.StatusOK, nil
}

// Dispatcher 请求调度器
type Dispatcher struct {
	queue      chan *ToolInvocation
	httpClient *HTTPClient
	guard      *RequestGuard
	adapter    *Adapter
	ctx        context.Context
	cancel     context.CancelFunc
	wg         sync.WaitGroup
}

// NewDispatcher 创建新的调度器
func NewDispatcher(size int, httpClient *HTTPClient, defaultTimeout int) *Dispatcher {
	ctx, cancel := context.WithCancel(context.Background())
	return &Dispatcher{
		queue:      make(chan *ToolInvocation, size),
		httpClient: httpClient,
		guard:      &RequestGuard{},
		adapter:    NewAdapter(defaultTimeout),
		ctx:        ctx,
		cancel:     cancel,
	}
}

// Start 启动调度器
func (d *Dispatcher) Start() {
	d.wg.Add(1)
	go d.worker()
}

// Stop 停止调度器
func (d *Dispatcher) Stop() {
	d.cancel()
	d.wg.Wait()
}

// Enqueue 入队请求
func (d *Dispatcher) Enqueue(invocation *ToolInvocation) error {
	select {
	case d.queue <- invocation:
		return nil
	case <-time.After(10 * time.Millisecond):
		return fmt.Errorf("queue is full")
	}
}

// worker 工作协程
func (d *Dispatcher) worker() {
	defer d.wg.Done()

	for {
		select {
		case <-d.ctx.Done():
			return
		case invocation := <-d.queue:
			d.processInvocation(invocation)
		}
	}
}

// processInvocation 处理调用
func (d *Dispatcher) processInvocation(invocation *ToolInvocation) {
	// 获取锁
	if err := d.guard.Acquire(); err != nil {
		invocation.ErrorCh <- err
		return
	}
	defer d.guard.Release()

	// 转换为批量请求
	questions, timeout, err := d.adapter.ToAskQuestionsRequest(invocation.ToolName, invocation.Params)
	if err != nil {
		invocation.ErrorCh <- err
		return
	}

	// 发送HTTP请求
	answers, cancelled, err := d.httpClient.AskQuestions(questions, timeout)
	if err != nil {
		invocation.ErrorCh <- err
		return
	}

	// 转换响应
	result, err := d.adapter.FromAskQuestionsResponse(invocation.ToolName, answers, cancelled)
	if err != nil {
		invocation.ErrorCh <- err
		return
	}

	invocation.ResponseCh <- result
}
